% Usar constraint logic programming over finite domains (clpfd)
:- use_module(library(clpfd)).

/*
* Generar la matriz con elementos sin inicializarlos todavia, reserva espacio de memoria para
* lo que se viene luego.
*/

make_Matrix(Matrix, X, Y) :-
    % Inicializa Matrix con 'X' elementos.
    length(Matrix,X),
    % Extiende cada fila con "Y" elementos.
    make_rows(Matrix, Y).

make_rows([], _ ).

make_rows([R|Rs], Len) :-
    % Inicializa R con 'Len' elementos
    length(R, Len),
    % Llama recursivamente hasta que Rs vacia osea para cada elemento de Matrix.
    make_rows(Rs, Len).

griddler(RowSpec, ColSpec, Matrix) :-
    maplist(row, RowSpec, Matrix),
    % Transpuesta para operar de la misma manera.
    transpose(Matrix, MatrixT),
    maplist(row, ColSpec, MatrixT).

row(Ks, Row) :-
    % Guardar en "Arcs" los arcos de cada fila
    phrase(arcs(Ks, Start, Final), Arcs),
    append(Row, [0], RowZ),writeln(Arcs),
    % Crea la tabla de transiciones
    automaton(RowZ, [source(Start), sink(Final)], [arc(Start,0,Start) | Arcs]).


% List of transition arcs for finite-state constraint.
arcs([], Final, Final) --> [].
arcs([K|Ks], CurState, Final) -->
    ( 
        { K == 0 } -> 
            [arc(CurState, 0, CurState), arc(CurState, 0, NextState)],arcs(Ks, NextState, Final) 
        ; 
            % Crea una transcion 1 y lo hace recursivamente para los N elementos consecutivos leidos
            [arc(CurState, 1, NextState)], { K1 #= K-1 }, arcs([K1|Ks], NextState, Final)
    ).


print_row([]) :- nl.
print_row([X|R]) :-
    (X == 0 -> write(' ') ; write('X') ),
    print_row(R).

read_file(Stream,[]) :-
    at_end_of_stream(Stream).

read_file(Stream,[X|L]) :-
    read(Stream,X),
    assert(X),
    read_file(Stream,L).

getRows(X, Rows) :-
    % Ordena las pistas por nro de fila
    findall(Nro-P, pistaHorizontal(Nro,P), L0), 
    keysort(L0,L1), 
    findall(P, member(_-P,L1), Rows),
    % Ver la longitud de la rows
    length(Rows,X).

getCols(Y, Cols) :-
    % Ordena las pistas por nro de columna
    findall(Nro-P, pistaVertical(Nro,P), L0), 
    keysort(L0,L1),
    findall(P, member(_-P,L1), Cols),
    % Ver la longitud de la cols
    length(Cols,Y).
    
main(InputFile) :-
    % olvidar lo que ya sabemos.
    retractall(pistaHorizontal(_,_)),
    retractall(pistaVertical(_,_)),

    % Lectura de pistas
    open(InputFile, read, Str),
    read_file(Str,_),
    close(Str),

    % Parser de conocimiento
    getRows(X, Rows),
    getCols(Y, Cols),

    % Resolver griddler/nonogram
    make_Matrix(Matrix, X, Y),
    griddler(Rows, Cols, Matrix),
    maplist(print_row, Matrix).